package com.util.fileUpload.impl;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;

import org.springframework.stereotype.Component;

import com.util.fileUpload.FileUploadProcessor;
import com.util.fileUpload.UploadFile;


@Component("defaultFileUpload")
public class DefaultFileUpload implements FileUploadProcessor {

	public String uploadOneFile(final UploadFile file) throws Exception {
		List<String> list = uploadFile(file);

		return list == null || list.size() == 0 ? null : list.get(0);
	}

	public List<String> uploadFile(UploadFile... files) throws Exception {
		List<String> results = new ArrayList<String>();

		for (UploadFile file : files) {
			String dirpath = file.getPath();
			String netPath = dirpath;

			dirpath = file.getBasePath() + dirpath;
			File dir = new File(dirpath);

			boolean mkdirSuccess = true;
			if (!dir.isDirectory()) {
				synchronized (DefaultFileUpload.class) {
					if (!dir.isDirectory()) {
						mkdirSuccess = dir.mkdirs();
					}
				}
			}
			if (!mkdirSuccess) { 	
				return Collections.emptyList();
			}

			Random rand = new Random();
		    int point = rand.nextInt(100)+1;
			
		    File src = file.getFile();
		    String fileName = md5(src) + System.currentTimeMillis() + point;
			netPath += fileName;

			StringBuffer targetFileName = new StringBuffer();
			targetFileName.append(dirpath).append(fileName);

			String fomate = file.getFormate();
			if (fomate != null && !"".equals(fomate)) {
				targetFileName.append(".").append(fomate);
				netPath += "." + fomate;
			}
			File target = new File(targetFileName.toString());
			if (copyFile(src, target)) {
				if ((file.getWidth() != null && file.getWidth()[0] != 0) && (file.getWidth() != null && file.getWidth()[0] != 0)) {
					getScaledImg(target, file.getWidth()[0], file.getWidth()[0], file.getFormate());
				}
				
				file.setLocalPath(target.getAbsolutePath());
			} else {
				//throw Exception();
			}
			results.add(netPath);
		}

		return results;
	}
	
	 public static String md5(File file) {
	        FileInputStream fin = null;
	        try {
	            fin = new FileInputStream(file);
	            byte[] b = new byte[8192];
	            int length = -1;
	            MessageDigest md = MessageDigest.getInstance("MD5");
	            while ((length = fin.read(b)) != -1) {
	                md.update(b, 0, length);
	            }
	            return md5(md.digest());
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            if (fin != null) {
	                try {
	                    fin.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
	        return null;
	    }
	 
	   public static String md5(byte b[]) {
	        int i;
	        StringBuffer buf = new StringBuffer("");
	        for (int offset = 0; offset < b.length; offset++) {
	            i = b[offset];
	            if (i < 0) i += 256;
	            if (i < 16) buf.append("0");
	            buf.append(Integer.toHexString(i));
	        }
	        return buf.toString();
	    }
	   
	   public static boolean copyFile(File src, File target) {
	        try {
	            int length = 2097152;
	            FileInputStream in = new FileInputStream(src);
	            RandomAccessFile out = new RandomAccessFile(target, "rw");
	            FileChannel inC = in.getChannel();
	            MappedByteBuffer outC = null;
	            MappedByteBuffer inbuffer = null;
	            byte[] b = new byte[length];
	            while (true) {
	                if (inC.position() == inC.size()) {
	                    inC.close();
	                    outC.force();
	                    out.close();
	                    return true;
	                }
	                if ((inC.size() - inC.position()) < length) {
	                    length = (int) (inC.size() - inC.position());
	                } else {
	                    length = 20971520;
	                }
	                b = new byte[length];
	                inbuffer = inC.map(MapMode.READ_ONLY, inC.position(), length);
	                inbuffer.load();
	                inbuffer.get(b);
	                outC = out.getChannel().map(MapMode.READ_WRITE, inC.position(), length);
	                inC.position(b.length + inC.position());
	                outC.put(b);
	                outC.force();
	            }
	        } catch (Exception e) {
	            e.printStackTrace();
	            return false;
	        }
	    }
	   
	   public static void getScaledImg(File F, int height, int width, String fmt) {
			try {
				double Ratio = 0.0; // 缩放比例
				if (!F.isFile()) {
					return;
				}
				BufferedImage Bi = ImageIO.read(F);
				int oheight = Bi.getHeight(), owidth = Bi.getWidth();
				if (height == -1) {
					if (width > 0 && owidth > width) {
						Ratio = Integer.valueOf(width).doubleValue() / owidth;
					} else {
						return;
					}
				} else if (width == -1) {
					if (height > 0 && oheight > height) {
						Ratio = Integer.valueOf(height).doubleValue() / oheight;
					} else {
						return;
					}
				} else if ((oheight > height) || (owidth > width)) {
					if (oheight > owidth) {
						Ratio = Integer.valueOf(height).doubleValue() / oheight;
					} else {
						Ratio = Integer.valueOf(width).doubleValue() / owidth;
					}
				} else {
					return;
				}
				AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(Ratio, Ratio), null);
				BufferedImage Itemp = op.filter(Bi, null);
				ImageIO.write(Itemp, fmt, F);
			} catch(Exception e) {
				e.printStackTrace();
			}
			
		}
	   
}
